package com.linsen.core.springdoc.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.linsen.core.common.annotation.AutoConfiguration;
import com.linsen.core.springdoc.props.LinsenSpringDocProperties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author zhaoyong
 * @date 2023/3/13
 */
@AutoConfiguration
@EnableConfigurationProperties({LinsenSpringDocProperties.class})
@ConditionalOnProperty(prefix = "linsen.springdoc", name = "enabled", havingValue = "true")
public class LinsenSpringDocAutoConfiguration {
    @Value("${server.port:8080}")
    private int port;
    @Value("${spring.mvc.servlet.path:/}")
    private String servletPath;

    @Bean
    public OpenAPI springDocOpenApi(LinsenSpringDocProperties springDocProperties) {
        if (ObjectUtil.isNull(springDocProperties)) {
            return new OpenAPI();
        }
        //配置认证、请求头参数
        Components components = new Components();
        List<SecurityRequirement> security = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(springDocProperties.getSecuritySchemes())) {
            for (Map.Entry<String, SecurityScheme> entry : springDocProperties.getSecuritySchemes().entrySet()) {
                components.addSecuritySchemes(entry.getKey(), entry.getValue());
                SecurityRequirement requirement = new SecurityRequirement();
                requirement.addList(entry.getKey());
                security.add(requirement);
            }
        }

        Info info = new Info();
        LinsenSpringDocProperties.PlusInfo plusInfo = springDocProperties.getInfo();
        if (plusInfo != null) {
            License license = new License();
            LinsenSpringDocProperties.PlusLicense plusLicense = plusInfo.getLicense();
            if (plusLicense != null) {
                license.name(plusLicense.getName()).url(plusLicense.getUrl());
            }
            Contact contact = new Contact();
            LinsenSpringDocProperties.PlusContact plusContact = plusInfo.getContact();
            if (plusContact != null) {
                contact.email(plusContact.getEmail()).name(plusContact.getName()).url(plusContact.getUrl());
            }
            info.title(plusInfo.getTitle()).description(plusInfo.getDescription())
                    .termsOfService(plusInfo.getTermsOfService()).version(plusInfo.getVersion() == null ? version() : plusInfo.getVersion())
                    .contact(contact).license(license)
            ;
        }
        // 接口调试路径
        List<Server> servers = springDocProperties.getServers();
        if (CollectionUtil.isEmpty(servers)) {
            servers = new ArrayList<>();
        }
        servers.add(localServer());
        return new OpenAPI().components(components)
                .servers(servers)
                .info(info).externalDocs(springDocProperties.getExternal())
                .security(security);
    }

    private Server localServer() {
        Server server = new Server();
        server.setUrl("http://localhost:" + port + "" + servletPath);
        server.setDescription("本地服务环境");
        return server;
    }

    private String version() {
        return "Spring Boot Version: " + SpringBootVersion.getVersion();
    }

}
